bitkeeper revision 1.33.2.1 (3e4e80bfKovSGNhpWOvbDx2coqfMIw)
authorrn@wyvis.camb.intel-research.net <rn@wyvis.camb.intel-research.net>
Sat, 15 Feb 2003 18:02:39 +0000 (18:02 +0000)
committerrn@wyvis.camb.intel-research.net <rn@wyvis.camb.intel-research.net>
Sat, 15 Feb 2003 18:02:39 +0000 (18:02 +0000)
clean up of time/timer code: No PIT timer anymore and bugfixes to timer code

xen-2.4.16/arch/i386/apic.c
xen-2.4.16/arch/i386/i8259.c
xen-2.4.16/arch/i386/setup.c
xen-2.4.16/arch/i386/time.c
xen-2.4.16/common/ac_timer.c
xen-2.4.16/common/schedule.c
xen-2.4.16/common/timer.c
xen-2.4.16/include/asm-i386/time.h

index 1fe5c16371cbeaa93fc63eb1a986d9107a7cf2f7..691240ad6130c7266eae7a00903fcc714acd315e 100644 (file)
@@ -697,37 +697,29 @@ int reprogram_ac_timer(s_time_t timeout)
  * the timer APIC on CPU does not go off every 10ms or so the linux 
  * timers loose accuracy, but that shouldn't be a problem.
  */
-//static s_time_t last_cpu0_tirq = 0;
+static s_time_t last_cpu0_tirq = 0;
 inline void smp_local_timer_interrupt(struct pt_regs * regs)
 {
        int cpu = smp_processor_id();
-       //s_time_t diff, now;
+       s_time_t diff, now;
+
 
     /* if CPU 0 do old timer stuff  */
        if (cpu == 0) {
 
-               /*
-         * XXX RN: the following code should be moved here or somewhere
-         * else. It's currently done using the 8255 timer interrupt, which
-         * I'd like to disable. But, APIC initialisation relies on it,
-         * e.g., timer interrupts coming in, jiffies going up, etc. Need to
-         * clean this up. Also see ./arch/i386/time.c
-         */
-#if 0
-               //update_time();/* XXX should use a timer for this */           
                now = NOW();
                diff = now - last_cpu0_tirq;
 
-               /* this uses three 64bit divisions which should be avoided!! */
-               if (diff >= MILLISECS(10)) {
-                       /* update jiffies */
-                       (*(unsigned long *)&jiffies) += diff / MILLISECS(10);
+               if (diff <= 0) {
+                       printk ("System Time went backwards: %lld\n", diff);
+                       return;
+               }
 
-                       /* do traditional linux timers */
+               while (diff >= MILLISECS(10)) {
                        do_timer(regs);
-                       last_cpu0_tirq = now;
+                       diff           -= MILLISECS(10);
+                       last_cpu0_tirq += MILLISECS(10);
                }
-#endif
        }
        /* call accurate timer function */
        do_ac_timer();
index 9c6ccc2d936c3e1f037a690141041a8474d9811e..645b7b0fefeb158c71516769dfdabc3b5bf4a70c 100644 (file)
@@ -467,3 +467,15 @@ void __init init_IRQ(void)
 
     setup_irq(2, &irq2);
 }
+
+/*
+ * we only need the timer interrupt for callibrating the tsc<->time<->bus cycle
+ * mappings. After this all timeing related functions should be run of the 
+ * APIC timers. This function allows us to disable the 
+ */
+void __init disable_pit(void)
+{
+        printk("Disable PIT. Not needed anymore\n");
+        /* This is not the most elegant way, but hey. */
+        disable_irq(0);
+}
index 63dac2cbe37be9a5f2277a7841ecf15a3326eed4..ad33a1e843063bf1ca9995ae71435766c272aabc 100644 (file)
@@ -280,6 +280,7 @@ void __init start_of_day(void)
     extern void tqueue_bh(void);
     extern void immediate_bh(void);
     extern void init_timervecs(void);
+       extern void disable_pit(void);
        extern void ac_timer_init(void);
     extern int  setup_network_devices(void);
     extern void net_init(void);
@@ -329,8 +330,11 @@ void __init start_of_day(void)
                       * fall thru to 8259A if we have to (but slower).
                       */
 #endif
-       init_xeno_time();       /* initialise the time */
+    initialize_keytable(); /* call back handling for key codes      */
+
+       disable_pit();          /* not needed anymore */
        ac_timer_init();    /* init accurate timers */
+       init_xeno_time();       /* initialise the time */
        schedulers_start(); /* start scheduler for each CPU */
 
     sti();
@@ -343,7 +347,7 @@ void __init start_of_day(void)
 #endif
     do_initcalls();
 
-    initialize_keytable(); /* call back handling for key codes      */
+
     initialize_serial();   /* setup serial 'driver' (for debugging) */
     initialize_keyboard(); /* setup keyboard (also for debugging)   */
 
index d090fe46bc07ae730227d5f751aeca537a31ed99..ef9417e88a05907a9521589402cfad3ca8367b92 100644 (file)
@@ -31,6 +31,7 @@
 #include <xeno/init.h>
 #include <xeno/interrupt.h>
 #include <xeno/time.h>
+#include <xeno/ac_timer.h>
 
 #include <asm/io.h>
 #include <xeno/smp.h>
@@ -74,15 +75,12 @@ static inline void do_timer_interrupt(int irq,
         spin_unlock(&i8259A_lock);
     }
 #endif
-
-       /* XXX RN: Want to remove this but APIC-SMP code seems to rely on it */
     do_timer(regs);
 }
 
 /*
- * This is the same as the above, except we _also_ save the current
- * Time Stamp Counter value at the time of the timer interrupt, so that
- * we later on can estimate the time of day more exactly.
+ * This is only temporarily. Once the APIC s up and running this 
+ * timer interrupt is turned off.
  */
 static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -303,8 +301,34 @@ void do_settimeofday(struct timeval *tv)
 /***************************************************************************
  * Update times
  ***************************************************************************/
-/* update hypervisors notion of time */
-void update_time(void) {
+
+/* update a domains notion of time */
+void update_dom_time(shared_info_t *si)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&stime_lock, flags);
+       si->system_time  = stime_now;
+       si->st_timestamp = stime_pcc;
+       spin_unlock_irqrestore(&stime_lock, flags);
+
+       spin_lock_irqsave(&wctime_lock, flags);
+       si->tv_sec       = wall_clock_time.tv_sec;
+       si->tv_usec      = wall_clock_time.tv_usec;
+       si->wc_timestamp = wctime_st;
+       si->wc_version++;
+       spin_unlock_irqrestore(&wctime_lock, flags);    
+
+       TRC(printk(" 0x%08X%08X\n", (u32)(wctime_st>>32), (u32)wctime_st));
+}
+
+/*
+ * Update hypervisors notion of time
+ * This is done periodically of it's own timer
+ */
+static struct ac_timer update_timer;
+static void update_time(unsigned long foo)
+{
        unsigned long  flags;
        u32                    new_pcc;
        s_time_t       new_st;
@@ -336,26 +360,12 @@ void update_time(void) {
        TRC(printk("TIME[%02d] update time: stime_now=%lld now=%lld,wct=%ld:%ld\n",
                           smp_processor_id(), stime_now, new_st, wall_clock_time.tv_sec,
                           wall_clock_time.tv_usec));
-}
-
-/* update a domains notion of time */
-void update_dom_time(shared_info_t *si)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&stime_lock, flags);
-       si->system_time  = stime_now;
-       si->st_timestamp = stime_pcc;
-       spin_unlock_irqrestore(&stime_lock, flags);
-
-       spin_lock_irqsave(&wctime_lock, flags);
-       si->tv_sec       = wall_clock_time.tv_sec;
-       si->tv_usec      = wall_clock_time.tv_usec;
-       si->wc_timestamp = wctime_st;
-       si->wc_version++;
-       spin_unlock_irqrestore(&wctime_lock, flags);    
-
-       TRC(printk(" 0x%08X%08X\n", (u32)(wctime_st>>32), (u32)wctime_st));
+       /* reload timer */
+ again:
+       update_timer.expires  = new_st + MILLISECS(200);
+       if(add_ac_timer(&update_timer) == 1) {
+               goto again;
+       }
 }
 
 /***************************************************************************
@@ -364,13 +374,15 @@ void update_dom_time(shared_info_t *si)
  ***************************************************************************/
 int __init init_xeno_time()
 {
-       int cpu = smp_processor_id();
-       u32     cpu_cycle;       /* time of one cpu cyle in pico-seconds */
-       u64 scale;
+       int      cpu = smp_processor_id();
+       u32          cpu_cycle;  /* time of one cpu cyle in pico-seconds */
+       u64      scale;      /* scale factor  */
 
        spin_lock_init(&stime_lock);
        spin_lock_init(&wctime_lock);
 
+       printk("Init Time[%02d]:\n", cpu);
+
        /* System Time */
        cpu_cycle   = (u32) (1000000000LL/cpu_khz); /* in pico seconds */
        scale = 1000000000LL << 32;
@@ -378,24 +390,30 @@ int __init init_xeno_time()
        st_scale_f = scale & 0xffffffff;
        st_scale_i = scale >> 32;
 
-       stime_now = (s_time_t)0;
-       rdtscl(stime_pcc);
-       
-       printk("Init Time[%02d]:\n", cpu);
-       printk(".... System Time: %lldns\n", NOW());
-       printk(".....cpu_cycle:   %u ps\n", cpu_cycle);
-       printk(".... st_scale_f:  %X\n",   st_scale_f);
-       printk(".... st_scale_i:  %X\n",   st_scale_i);
-       printk(".... stime_pcc:   %u\n",   stime_pcc);
-
        /* Wall Clock time */
        wall_clock_time.tv_sec  = get_cmos_time();
        wall_clock_time.tv_usec = 0;
+
+       /* set starting times */
+       stime_now = (s_time_t)0;
+       rdtscl(stime_pcc);
        wctime_st = NOW();
 
+       /* start timer to update time periodically */
+       init_ac_timer(&update_timer);
+       update_timer.function = &update_time;
+       update_time(0);
+
+       printk(".... System Time: %lldns\n", NOW());
+       printk(".....cpu_cycle:   %u ps\n",  cpu_cycle);
+       printk(".... st_scale_f:  %X\n",     st_scale_f);
+       printk(".... st_scale_i:  %X\n",     st_scale_i);
+       printk(".... stime_pcc:   %u\n",     stime_pcc);
+
        printk(".... Wall Clock:  %lds %ldus\n", wall_clock_time.tv_sec,
                   wall_clock_time.tv_usec);
        printk(".... wctime_st:   %lld\n", wctime_st);
+
        return 0;
 }
 
index b20efc94c9682f3492fd8c4043b0537c6a9a037b..a46ec53d4405009762a12eba13edc0af9470951f 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <xeno/time.h>
 #include <xeno/ac_timer.h>
+#include <xeno/keyhandler.h>
 
 #include <asm/system.h>
 #include <asm/desc.h>
@@ -80,8 +81,6 @@ int add_ac_timer(struct ac_timer *timer)
 {
        int                      cpu = smp_processor_id();
        unsigned long    flags;
-       struct list_head *tmp, *prev;
-       struct ac_timer  *t;
        s_time_t                 now;
 
        /* sanity checks */
@@ -96,42 +95,54 @@ int add_ac_timer(struct ac_timer *timer)
                           (u32)(timer->expires>>32), (u32)timer->expires);
                return 1;
        }
-
-       local_irq_save(flags);
-
-       /* check if timer would be inserted at start of list */
-       if ((list_empty(&ac_timers[cpu].timers)) ||
-               (timer->expires <
-               (list_entry(&ac_timers[cpu].timers,
-                                       struct ac_timer, timer_list))->expires)) {
-
-               TRC(printk("ACT  [%02d] add(): add at head\n", cpu));
+       spin_lock_irqsave(&ac_timers[cpu].lock, flags);
+       /*
+     * Add timer to the list. If it gets added to the front we have to
+     * reprogramm the timer
+     */
+       if (list_empty(&ac_timers[cpu].timers)) {
                /* Reprogramm and add to head of list */
                if (!reprogram_ac_timer(timer->expires)) {
                        /* failed */
-                       TRC(printk("ACT  [%02d] add(): add at head failed\n", cpu));
-                       local_irq_restore(flags);
+                       printk("ACT  [%02d] add(): add at head failed\n", cpu);
+                       spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
                        return 1;
                }
                list_add(&timer->timer_list, &ac_timers[cpu].timers);
-               
+               TRC(printk("ACT  [%02d] add(0x%08X%08X): added at head\n", cpu,
+                                  (u32)(timer->expires>>32), (u32)timer->expires));
        } else {
-               /* find correct entry and add timer */
-               prev = &ac_timers[cpu].timers;
-               list_for_each(tmp, &ac_timers[cpu].timers) {
-                       t = list_entry(tmp, struct ac_timer, timer_list);
-                       if (t->expires < timer->expires) {
-                               list_add(&timer->timer_list, prev);
-                               TRC(printk("ACT  [%02d] add(): added between %lld and %lld\n",
-                                          cpu,
-                                          list_entry(prev,struct ac_timer,timer_list)->expires,
-                                          list_entry(tmp,struct ac_timer,timer_list)->expires));
+               struct list_head *pos;
+               struct ac_timer  *t;
+               for (pos = ac_timers[cpu].timers.next;
+                        pos != &ac_timers[cpu].timers;
+                        pos = pos->next) {
+                       t = list_entry(pos, struct ac_timer, timer_list);
+                       if (t->expires > timer->expires)
                                break;
+               }
+
+               if (pos->prev == &ac_timers[cpu].timers) {
+                       /* added to head, reprogramm timer */
+                       if (!reprogram_ac_timer(timer->expires)) {
+                               /* failed */
+                               TRC(printk("ACT  [%02d] add(): add at head failed\n", cpu));
+                               spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
+                               return 1;
                        }
-                       prev = tmp;
+                       list_add (&(timer->timer_list), pos->prev);
+                       TRC(printk("ACT  [%02d] add(0x%08X%08X): added at head\n", cpu,
+                                          (u32)(timer->expires>>32), (u32)timer->expires));
+               } else {
+                       list_add (&(timer->timer_list), pos->prev);
+                       TRC(printk("ACT  [%02d] add(0x%08X%08X): add < exp=0x%08X%08X\n",
+                                          cpu,
+                                          (u32)(timer->expires>>32), (u32)timer->expires,
+                                          (u32)(t->expires>>32), (u32)t->expires));
                }
+
        }
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
        return 0;
 }
 
@@ -158,16 +169,17 @@ static int detach_ac_timer(struct ac_timer *timer)
  */
 int rem_ac_timer(struct ac_timer *timer)
 {
-       int res;
+       int               cpu = smp_processor_id();
+       int           res;
        unsigned long flags;
-       TRC(int cpu = smp_processor_id());
 
        TRC(printk("ACT  [%02d] remove(): timo=%lld \n", cpu, timer->expires));
        /* sanity checks */
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&ac_timers[cpu].lock, flags);
        res = detach_ac_timer(timer);   
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
+
        return res;
 }
 
@@ -199,7 +211,7 @@ void do_ac_timer(void)
        struct ac_timer  *t;
        struct list_head *tmp;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&ac_timers[cpu].lock, flags);
 
  do_timer_again:
 
@@ -210,7 +222,7 @@ void do_ac_timer(void)
     /* empty time list  */
        if (list_empty(&ac_timers[cpu].timers)) {
                printk("ACT[%02d] do_ac_timer(): timer irq without timer\n", cpu);
-               local_irq_restore(flags);
+               spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
                return;
        }
 
@@ -219,6 +231,8 @@ void do_ac_timer(void)
        t = list_entry(ac_timers[cpu].timers.next, struct ac_timer, timer_list);
        detach_ac_timer(t);
 
+       spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
+
 
 #ifdef AC_TIMER_STATS
        {
@@ -258,6 +272,9 @@ void do_ac_timer(void)
 
        /* check if there are other timer functions on the list */
        now = NOW();
+
+       spin_lock_irqsave(&ac_timers[cpu].lock, flags);
+
        if (!list_empty(&ac_timers[cpu].timers)) {
                list_for_each(tmp, &ac_timers[cpu].timers) {
                        t = list_entry(tmp, struct ac_timer, timer_list);
@@ -265,8 +282,10 @@ void do_ac_timer(void)
                                           cpu, now, t->expires));
                        if (t->expires <= now) {
                                detach_ac_timer(t);
+                               spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
                                if (t->function != NULL)
                                        t->function(t->data);
+                               spin_lock_irqsave(&ac_timers[cpu].lock, flags);
                                now = NOW();
                        } else {
                                TRC(printk("ACT  [%02d] do(): break1\n", cpu));
@@ -286,7 +305,47 @@ void do_ac_timer(void)
                        }
                }
        }
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
+       TRC(printk("ACT  [%02d] do(): end\n", cpu));
+}
+
+/*
+ * debug dump_queue
+ * arguments: queue head, name of queue
+ */
+static void dump_tqueue(struct list_head *queue, char *name)
+{
+    struct list_head *list;
+    int loop = 0;
+       struct ac_timer  *t;
+
+    printk ("QUEUE %s %lx   n: %lx, p: %lx\n", name,  (unsigned long)queue,
+            (unsigned long) queue->next, (unsigned long) queue->prev);
+    list_for_each (list, queue) {
+               t = list_entry(list, struct ac_timer, timer_list);
+        printk ("  %s %d : %lx ex=0x%08X%08X %lu  n: %lx, p: %lx\n",
+                               name, loop++, 
+                (unsigned long)list,
+                               (u32)(t->expires>>32), (u32)t->expires, t->data,
+                (unsigned long)list->next, (unsigned long)list->prev);
+    }
+    return; 
+}
+
+
+static void dump_timerq(u_char key, void *dev_id, struct pt_regs *regs)
+{
+    u_long   flags; 
+       s_time_t now = NOW();
+
+    printk("Dumping ac_timer queues for cpu 0: NOW=0x%08X%08X\n",
+                  (u32)(now>>32), (u32)now); 
+       
+    spin_lock_irqsave(&ac_timers[0].lock, flags);
+    dump_tqueue(&ac_timers[0].timers, "ac_time"); 
+    spin_unlock_irqrestore(&ac_timers[0].lock, flags);
+       printk("\n");
+    return; 
 }
 
 /*
@@ -303,5 +362,6 @@ void __init ac_timer_init(void)
                INIT_LIST_HEAD(&ac_timers[i].timers);
                spin_lock_init(&ac_timers[i].lock);
     }
-       /* ac_timer_debug(0); */
+
+       add_key_handler('a', dump_timerq, "dump ac_timer queues");
 }
index a1c0c406ee72360cd7095f30414d9f40ea1e2ced..289e69374bfb2208ca205e3268ecfb57feb020ae 100644 (file)
@@ -282,6 +282,9 @@ asmlinkage void schedule(void)
     return;
 }
 
+/*
+ * The scheduling timer.
+ */
 static __cacheline_aligned int count[NR_CPUS];
 static void sched_timer(unsigned long foo)
 {
@@ -290,14 +293,35 @@ static void sched_timer(unsigned long foo)
        s_time_t                        now;
        int                             res;
 
+       /* reschedule after each 5 ticks */
        if (count[cpu] >= 5) {
                set_bit(_HYP_EVENT_NEED_RESCHED, &curr->hyp_events);
                count[cpu] = 0;
-               if (cpu == 0)
-                       update_time(); /* XXX RN: Should be moved on its own timer */
        }
        count[cpu]++;
 
+       /*
+     * deliver virtual timer interrups to domains if we are CPU 0
+     * XXX RN: We don't have a per CPU list of domains yet. Otherwise 
+     * would use that. Plus, this should be removed anyway once
+     * Domains "know" about virtual time and timeouts. But, it's better
+     * here then where it was before.
+     */
+       if (cpu == 0) {
+               struct task_struct *p;
+               unsigned long cpu_mask = 0;
+
+               /* send virtual timer interrupt */
+               read_lock(&tasklist_lock);
+               p = &idle0_task;
+               do {
+                       cpu_mask |= mark_guest_event(p, _EVENT_TIMER);
+               }
+               while ( (p = p->next_task) != &idle0_task );
+               read_unlock(&tasklist_lock);
+               guest_event_notify(cpu_mask);
+       }
+
  again:
        now = NOW();
        s_timer[cpu].expires  = now + MILLISECS(10);
@@ -310,6 +334,8 @@ static void sched_timer(unsigned long foo)
                goto again;
 
 }
+
+
 /*
  * Initialise the data structures
  */
index da0452249e50cbca8ce8690084f0b975ec344526..20d45ccbe664d4223d2e098e2e3011393535ae25 100644 (file)
@@ -586,27 +586,12 @@ void timer_bh(void)
 
 void do_timer(struct pt_regs *regs)
 {
-    struct task_struct *p;
-    shared_info_t *s;
-    unsigned long cpu_mask = 0;
 
     (*(unsigned long *)&jiffies)++;
 
     if ( !using_apic_timer )
         update_process_times(user_mode(regs));
 
-       /* XXX RN: Move this for virtual domain time timer interrupts */
-    read_lock(&tasklist_lock);
-    p = &idle0_task;
-    do {
-        s = p->shared_info;
-        cpu_mask |= mark_guest_event(p, _EVENT_TIMER);
-    }
-    while ( (p = p->next_task) != &idle0_task );
-    read_unlock(&tasklist_lock);
-
-    guest_event_notify(cpu_mask);
-
     mark_bh(TIMER_BH);
     if (TQ_ACTIVE(tq_timer))
         mark_bh(TQUEUE_BH);
index 9825847be12589792b5f63cf05e1463552f99f92..2f834908a73d6431923a5d44a04cbd857841dc10 100644 (file)
@@ -41,9 +41,6 @@ typedef s64      s_time_t;         /* System time */
 extern  u32      stime_pcc;      /* cycle counter value at last timer irq */
 extern  s_time_t stime_now;      /* time in ns at last timer IRQ */
 
-/* update time variables once in a while */
-extern void update_time(void);
-
 /*
  * Domain Virtual Time
  */